
import java.io.PrintWriter;
import java.util.BitSet;
import java.util.ArrayList;

public class ContingencyTable {
	
	private static final int BIT_ZERO = 0x00000000;
	private static final int BIT_ONE =  0xffffffff;
	
	private HypothesisParameters parameters;
	
	private int andAntecedent;  //must be true
	private int orAntecedent; 	//must be false
	
	private int andSuccedent;  //must be true
	private int orSuccedent; 	//must be false
	
	private int bothTrueA = 0;
	private int anteTrueB = 0;
	private int succTrueC = 0;
	private int noneTrueD = 0;
	
	ContingencyTable( HypothesisParameters parameters)
	{
		this.parameters = parameters;
		
		andAntecedent = BIT_ZERO;
		for (int index: parameters.trueIndecesAnte)
		{
			int andVal = 1 << index;
			andAntecedent = andAntecedent | andVal;
		}
		
		orAntecedent = BIT_ONE;
		for (int index: parameters.falseIndecesAnte)
		{
			int andVal = 1 << index;
			orAntecedent = orAntecedent | (~andVal);
		}
		
		andSuccedent = BIT_ZERO;
		for (int index: parameters.trueIndecesSucc)
		{
			int andVal = 1 << index;
			andSuccedent = andSuccedent | andVal;
		}
		
		orSuccedent = BIT_ONE;
		for (int index: parameters.falseIndecesSucc)
		{
			int andVal = 1 << index;
			orSuccedent = orSuccedent | (~andVal);
		}
	}
	
	public void countSong( SongBits song )
	{
		int songBits = song.getBits();
		
		/*
		System.out.println( "song: " + Integer.toBinaryString( songBits) );
		System.out.println( "and : " +Integer.toBinaryString(andAntecedent));
		System.out.println( "or  : "+Integer.toBinaryString(orAntecedent));
		*/
		
		boolean anteFlag = ( (songBits & andAntecedent) == andAntecedent
							&& (songBits | orAntecedent) == orAntecedent );
		boolean succFlag = ( (songBits & andSuccedent) == andSuccedent
				&& (songBits | orSuccedent) == orSuccedent );
		if (anteFlag && succFlag )
		{
			bothTrueA++;
		}
		else if (anteFlag)
		{
			anteTrueB++;
		}
		else if (succFlag)
		{
			succTrueC++;
		}
		else
		{
			noneTrueD++;
		}		
	}
	
	public String getResult( double pQuantifier, int tMinMatch, PrintWriter output)
	{
		output.println("Table: " + parameters.getAnteString(true) + " ~ " + parameters.getSuccString(true) );
		output.println(bothTrueA + "  |  " + anteTrueB);
		output.println("------------------------------");
		output.println(succTrueC + "  |  " + noneTrueD);
		output.println();
		
		int total = bothTrueA +anteTrueB + succTrueC + noneTrueD;
		
		String fullResult = "";
		//A case
		double highVal = ((double) bothTrueA) / (bothTrueA + anteTrueB);
		double lowVal = ( (double) (1 + pQuantifier) * (bothTrueA + succTrueC) ) / total;
		if ( highVal >= lowVal && bothTrueA >= tMinMatch)	
		{
			String result = "";
			result += parameters.getAnteString(true);
			result += " => ";
			result += parameters.getSuccString(true);
			fullResult += result;
		}
		
		//B case
		highVal = ((double) anteTrueB) / (bothTrueA + anteTrueB);
		lowVal = ( (double) (1 + pQuantifier) * (anteTrueB + noneTrueD) ) / total;
		if ( highVal >= lowVal && anteTrueB >= tMinMatch)	
		{
			String result = "";
			result += parameters.getAnteString(true);
			result += " => ";
			result += parameters.getSuccString(false);
			if (!fullResult.isEmpty())
			{
				fullResult += "\n";
			}
			fullResult += result;
		}
		
		//C case
		highVal = ((double) succTrueC) / (succTrueC + noneTrueD);
		lowVal = ( (double) (1 + pQuantifier) * (succTrueC + bothTrueA) ) / total;
		if ( highVal >= lowVal && succTrueC >= tMinMatch)	
		{
			String result = "";
			result += parameters.getAnteString(false);
			result += " => ";
			result += parameters.getSuccString(true);
			if (!fullResult.isEmpty())
			{
				fullResult += "\n";
			}
			fullResult += result;
		}
		
		//D case
		highVal = ((double) noneTrueD) / (succTrueC + noneTrueD);
		lowVal = ( (double) (1 + pQuantifier) * (noneTrueD + anteTrueB) ) / total;
		if ( highVal >= lowVal && noneTrueD >= tMinMatch)	
		{
			String result = "";
			result += parameters.getAnteString(false);
			result += " => ";
			result += parameters.getSuccString(false);
			if (!fullResult.isEmpty())
			{
				fullResult += "\n";
			}
			fullResult += result;
		}
		
		
		return fullResult;
	}
	
}
